home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 1.iso / toolbox / src / exampleCode / opengl / extensions / samples / videobub.c < prev    next >
C/C++ Source or Header  |  1996-11-11  |  16KB  |  609 lines

  1. /*
  2.  * Copyright (c) 1994 Silicon Graphics, Inc.
  3.  * 
  4.  * Permission to use, copy, modify, distribute, and sell this software and
  5.  * its documentation for any purpose is hereby granted without fee,
  6.  * provided that (i) the above copyright notices and this permission
  7.  * notice appear in all copies of the software and related documentation,
  8.  * and (ii) the name of Silicon Graphics may not be used in any
  9.  * advertising or publicity relating to the software without the specific,
  10.  * prior written permission of Silicon Graphics.
  11.  * 
  12.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
  13.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
  14.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  15.  * 
  16.  * IN NO EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL,
  17.  * INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY
  18.  * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  19.  * OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
  20.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  21.  * OF THIS SOFTWARE.
  22.  */
  23. /*
  24.  * vidtobub.c
  25.  *
  26.  * Demonstrate video-to-texture transfers from Sirius in OpenGL.
  27.  *
  28.  * The program "simulates" soap bubbles floating in front of a live video
  29.  * image.
  30.  *
  31.  * Algorithm:
  32.  *   The video frame are copied to texture memory.
  33.  *
  34.  *   A polygon that covers the window is drawn with the texture mapped onto
  35.  *   it in a "1-1" ratio for the underlying video image.
  36.  *
  37.  *   The "bubbles" are sphere like spline meshes that move across the image.
  38.  *   The see through and "lens" warping is achieved by mapping the texture onto
  39.  *   the bubble with some streching of the texture coordinates, thus mapping
  40.  *   "more" texture onto the bubble.  To movement of the bubble across the image
  41.  *   is accounted for by adjusting the texture matrix for each bubble according
  42.  *   to the relative position of the bubble.
  43.  *
  44.  * See the usage() function for the command line options (or run with -h).
  45.  *  
  46.  * $Revision: 1.1 $
  47.  */
  48.  
  49. #include <stdlib.h>
  50. #include <stdio.h>
  51. #include <math.h>
  52. #include <getopt.h>
  53. #include <device.h>
  54. #include <vl/vl.h>
  55. #include <vl/dev_sirius.h>
  56. #include <GL/glx.h>
  57. #include <GL/glu.h>
  58. #include <X11/keysym.h>
  59. #include "xwindow.h"
  60.  
  61. #define XSIZE 64.0
  62. #define YSIZE 64.0
  63. #define WINSCALE 1.8
  64.  
  65. typedef struct {
  66.     int ssize, tsize;
  67.     int x, y;
  68.     int dx, dy;
  69. } Bubble;
  70.  
  71.  
  72. GLfloat texture_matrix[4][4] = {
  73.     1, 0, 0, 0,
  74.     0, 1, 0, 0,
  75.     0, 0, 1, 0,
  76.     0, 0, 0, 1
  77. };
  78.  
  79. /*
  80.  * texture variables
  81.  */
  82. float    s_scale, t_scale, s_fraction, t_fraction;
  83.  
  84. /*
  85.  * VL variables
  86.  */
  87. VLControlValue size, timing;
  88. VLControlValue   format;
  89. VLControlValue   cap_type;
  90. VLServer    svr;
  91. VLPath    path;
  92. VLNode    src;
  93. VLNode    drn;
  94.  
  95.  
  96. /* OpenGL/X variables */
  97. Display *dpy;
  98. Window window;
  99. #ifdef GLX_SGIX_video_source
  100. GLXVideoSourceSGIX glxVideoSource;
  101. #else  /* Make the compiler barf */
  102. GLX_SGIX_video_source is not defined in this version of the library
  103. #endif
  104.  
  105. /*
  106.  * function prototypes
  107.  */
  108. void usage(char *, int);
  109. void initVideo(int, int, int);
  110. void initGfx(int, char **);
  111. int CreateTexture(void);
  112. void DisplayNewFrame(void);
  113. void cleanup(void);
  114. void ProcessEvents(void);
  115. void UpdateTimingFormat(void);
  116.  
  117. int t_width, t_height;
  118.  
  119. /**************************************************************************/
  120.  
  121. #define ORDER 4
  122. #define SEGMENTS 12
  123.  
  124. int s_points, t_points;
  125. int s_stride, t_stride;
  126. int comps = 3;
  127.  
  128. int drawmap = 1;
  129.  
  130. GLfloat *tmap, *vmap;
  131.  
  132. int numBubbles = 0;
  133. Bubble bubs[100];
  134.  
  135. /*
  136.  * Create a bubble at x,y with randomize speed.
  137.  */
  138. void
  139. make_bubble(int x, int y)
  140. {
  141.     Bubble *b = &bubs[numBubbles];
  142.  
  143.     b->ssize = b->tsize = 70 + (unsigned)(rand() & 0x3c);
  144.     b->x = x/WINSCALE - b->ssize/2;
  145.     b->y = (size.xyVal.y * WINSCALE - y - 1)/WINSCALE - b->tsize/2;
  146.     b->dx = (2 + (rand() & 0x03)) * (rand() & 0x1 ? 1 : -1 );
  147.     b->dy = (2 + (rand() & 0x03)) * (rand() & 0x1 ? 1 : -1 );
  148.     numBubbles++;
  149. }
  150.  
  151. /*
  152.  * Setup the evaluator maps that are going to be used for drawing the
  153.  * bubbles.
  154.  */
  155. void
  156. setupMaps(void)
  157. {
  158.     int s, t;
  159.     float cs, ct, s1, t1, d0, d1, mx, scale;
  160.     double fs1, ft1;
  161.     GLfloat *vertcp, *texcp;
  162.  
  163.     s_points = ORDER;
  164.     t_points = ORDER;
  165.     s_stride = comps;
  166.     t_stride = comps * s_points;
  167.     
  168.     vertcp = vmap = malloc(s_points * t_points * comps * sizeof(GLfloat));
  169.     texcp = tmap = malloc(s_points * t_points * comps * sizeof(GLfloat));
  170.     cs = (s_points - 1)/2.0;
  171.     ct = (t_points - 1)/2.0;
  172.     for (t=0; t < t_points; t++) {
  173.     for (s=0; s < s_points; s++) {
  174.  
  175.         /* distances from control point to center of patch */
  176.         s1 = s - cs;
  177.         t1 = t - ct;
  178.         fs1 = fabs(s1);
  179.         ft1 = fabs(t1);
  180.  
  181.         /* warp vertex control points to make it a disk */
  182.         if (s1 == 0 && t1 == 0) {
  183.         scale = 1; 
  184.         } else {
  185.         mx = fs1 > ft1 ? fs1 : ft1;
  186.         if (fs1 == ft1) {
  187.             /* extra tug at the corners to make it more round */
  188.             mx *= 0.85;
  189.         }
  190.         scale = mx/sqrt(s1 * s1 + t1 * t1);
  191.         }
  192.         vertcp[0] = cs + (s1 * scale);
  193.         vertcp[1] = ct + (t1 * scale);
  194.         vertcp[2] = 0;
  195.         vertcp += comps;
  196.  
  197.         /* warp texture coord control points to make it a bubble */
  198.         if (s1 == 0 && t1 == 0) {
  199.         scale = 1; 
  200.         } else {
  201.         mx = fs1 > ft1 ? fs1 : ft1;
  202.         if (mx == cs - 2 || mx == 0.5) {
  203.             /* push outward */
  204.             mx += 8;
  205.         } else if (mx == cs - 1) {
  206.             /* push inward */
  207.             mx += -0.5;
  208.         }
  209.         scale = fabs(mx)/sqrt(s1 * s1 + t1 * t1);
  210.         }
  211.         texcp[0] = cs + (s1 * scale);
  212.         texcp[1] = ct + (t1 * scale);
  213.         texcp[2] = 0;
  214.         texcp += comps;
  215.     }
  216.     }
  217.     glMapGrid2f(SEGMENTS, 0, 1, SEGMENTS, 0, 1);
  218. }
  219.  
  220. unsigned char white[] = { 0xff, 0xff, 0xff };
  221. unsigned char gray[]  = { 0x80, 0x80, 0x80 };
  222. int ssize = 1024, tsize = 512;
  223.  
  224. /*
  225.  * Draw a single bubble by mapping the texture with the correct offset onto
  226.  * the bubble.
  227.  */
  228. void
  229. drawBubble( Bubble *bub )
  230. {
  231.     int is, it;
  232.     float *p;
  233.     float bw, bh, bx, by, s0, s1, t0, t1;
  234.     
  235.     bw = bub->ssize;
  236.     bh = bub->tsize;
  237.     bx = bub->x;
  238.     by = bub->y;
  239.  
  240.     glMatrixMode(GL_TEXTURE);
  241.     glLoadMatrixf((GLfloat *) texture_matrix);
  242.     glScalef(1.0/size.xyVal.x, 1.0/size.xyVal.y, 1); 
  243.     glTranslatef(bx, by, 0);
  244.     glScalef(bw/(s_points - 1), bh/(t_points - 1), 1);
  245.  
  246.     glMatrixMode(GL_MODELVIEW);
  247.     glLoadIdentity();
  248.     
  249.     glTranslatef(bx, by, 0);
  250.     glScalef(bw/(s_points - 1), bh/(t_points - 1), 1);
  251.     
  252.     glEnable(GL_TEXTURE_2D);
  253.  
  254.     glEnable(GL_MAP2_TEXTURE_COORD_2);
  255.     glEnable(GL_MAP2_VERTEX_3);
  256.  
  257.     for (it=0; it < 1; it++) {
  258.         for (is=0; is < 1; is++) {
  259.             p = vmap + it * t_stride * (ORDER - 1) +
  260.                 is * s_stride * (ORDER - 1);
  261.             glMap2f(GL_MAP2_VERTEX_3, 0, 1,
  262.                     s_stride, 4, 0, 1, t_stride, 4, p);
  263.  
  264.             p = tmap + it * t_stride * (ORDER - 1) +
  265.                 is * s_stride * (ORDER - 1);
  266.             glMap2f(GL_MAP2_TEXTURE_COORD_2, 0, 1,
  267.                     s_stride, 4, 0, 1, t_stride, 4, p);
  268.         
  269.             glEvalMesh2(GL_FILL, 0, SEGMENTS, 0, SEGMENTS);
  270.         }
  271.     }
  272.     glDisable(GL_TEXTURE_2D);
  273.     
  274.     bub->x += bub->dx;
  275.     bub->y += bub->dy;
  276.     if (bub->x > size.xyVal.x)
  277.         bub->x = 0;
  278.     else if (bub->x < 0)
  279.         bub->x = size.xyVal.x;
  280.     if (bub->y > size.xyVal.y)
  281.         bub->y = 0;
  282.     else if (bub->y < 0)
  283.         bub->y = size.xyVal.y;
  284. }
  285.  
  286. /**************************************************************************/
  287.  
  288. int
  289. main(int argc, char **argv)
  290. {
  291.  
  292.     int        c, insrc = VL_ANY;
  293.     int     device = VL_ANY;
  294.     short    dev, val;
  295.     int        packingFormat = 5;
  296.  
  297.     /* Parse the input string */
  298.     while ((c = getopt(argc, argv, "n:v:t:s:i:o:M:hFG")) != EOF ) {
  299.         switch (c) {
  300.       case 'n':
  301.         device = atoi(optarg); /* user can override default device */
  302.         break;
  303.       case 't':
  304.         packingFormat = atoi(optarg);
  305.         break;
  306.       case 'v':
  307.         insrc = atoi(optarg);
  308.         break;
  309.       case 'h':
  310.         usage(argv[0], EXIT_SUCCESS);
  311.       default:
  312.         usage(argv[0], EXIT_FAILURE);
  313.         }
  314.     }
  315.  
  316.     initVideo(insrc, device, packingFormat);
  317.  
  318.     initGfx(argc, argv);
  319.  
  320.     vlBeginTransfer(svr, path, 0, NULL);
  321.  
  322.     while (TRUE) {
  323.     if (XEventsQueued(dpy, QueuedAfterReading)) {
  324.         XEvent event;
  325.  
  326.         XNextEvent(dpy, &event);
  327.         switch (event.type) {
  328.           case ButtonPress:
  329.                 make_bubble(((XButtonEvent *) &event)->x,
  330.                             ((XButtonEvent *) &event)->y);
  331.                 break;
  332.           case KeyPress: {
  333.                   KeySym key;
  334.                   (void) XLookupString(&event.xkey, NULL, 0, &key, NULL);
  335.                   switch (key) {
  336.                     case XK_Escape:
  337.                       exit(EXIT_FAILURE);
  338.                       break;
  339.                     case XK_h:
  340.                     case XK_H:
  341.                     case XK_question:
  342.                       printf("Keys:\Mouse buttons - create bubbles\n");
  343.                       printf("\th/? - help\n");
  344.                       printf("\tEsc - quit\n");
  345.                       break;
  346.                   }
  347.               }
  348.             }
  349.     }
  350.     /* Check for VL events if any ... */
  351.     ProcessEvents();
  352.     /* Next frame of data */
  353.     DisplayNewFrame();
  354.         glXSwapBuffers(dpy, window);
  355.     }
  356. }
  357.  
  358. void
  359. usage(char *name, int exitStatus)
  360. {
  361.     fprintf(stderr, "usage: %s [-n#] [-v#] [-t#] [-h (for help)]\n", name);
  362.     fprintf(stderr, "\t-n#  video device number (as reported by vlinfo)\n");
  363.     fprintf(stderr, "\t-v#  video input number (as reported by vlinfo)\n");
  364.     fprintf(stderr, "\t-t#  texture format (as packed by Sirius)\n");
  365.     fprintf(stderr,
  366.             "\tInteractively, `h/?' keys provide description of interface\n");
  367.     exit(exitStatus);
  368. }
  369.  
  370. void
  371. initVideo(int insrc, int device, int packingFormat)
  372. {
  373.     VLControlValue tex;
  374.  
  375.     /* open the server */
  376.     if (!(svr = vlOpenVideo(""))) {
  377.     printf("couldn't open video\n");
  378.     exit(EXIT_FAILURE);
  379.     }
  380.  
  381.     /* Get the Video source */
  382.     src = vlGetNode(svr, VL_SRC, VL_VIDEO, insrc);
  383.     /* Get the Texture drain */
  384.     drn = vlGetNode(svr, VL_DRN, VL_TEXTURE, 0);
  385.  
  386.     /* Create path   */
  387.     path = vlCreatePath(svr, device, src, drn);
  388.     if (path < 0) {
  389.     vlPerror("vlCreatePath");
  390.     exit(EXIT_FAILURE);
  391.     }
  392.  
  393.     /* setup path */
  394.     if (vlSetupPaths(svr, (VLPathList)&path, 1, VL_SHARE, VL_SHARE) < 0) {
  395.     vlPerror("vlSetupPaths");
  396.     exit(EXIT_FAILURE);
  397.     }
  398.     /* select the appropriate events */
  399.     if (vlSelectEvents(svr, path, VLStreamPreemptedMask |
  400.                        VLControlChangedMask ) < 0) {
  401.         vlPerror("Select Events");
  402.         exit(EXIT_FAILURE);
  403.     }
  404.     cap_type.intVal = VL_CAPTURE_INTERLEAVED;
  405.     
  406.     if (vlSetControl(svr, path, drn, VL_CAP_TYPE, &cap_type) <0) {
  407.     vlPerror("VlSetControl");
  408.     exit(EXIT_FAILURE);
  409.     }
  410.     UpdateTimingFormat();
  411.     /* Set the Texture packing mode */
  412.     switch(packingFormat) {
  413.       case 4:
  414.         tex.intVal = SIR_TEX_PACK_RGBA_4;
  415.         break;
  416.       case 5:
  417.         tex.intVal = SIR_TEX_PACK_RGB_5;
  418.         break;
  419.       case 8:
  420.         tex.intVal = SIR_TEX_PACK_RGBA_8;
  421.         break;
  422.       default:
  423.         tex.intVal = SIR_TEX_PACK_RGB_5;
  424.         break;
  425.     }
  426.  
  427.     if (vlSetControl(svr, path, drn, VL_PACKING, &tex) <0) {
  428.         vlPerror("VlSetControl");
  429.         exit(EXIT_FAILURE);
  430.     }
  431. }
  432.  
  433. /*
  434.  * InitGfx:
  435.  *  Initialize the graphics.
  436.  *  Window size is base of the video format as determined by
  437.  *  the timing bvaluse on the source node.
  438.  */
  439. void
  440. initGfx(int argc, char **argv)
  441. {
  442.     GLXContext ctx;
  443.     int visualAttr[] = {GLX_RGBA, GLX_DOUBLEBUFFER, GLX_RED_SIZE, 1,
  444.                         GLX_DEPTH_SIZE, 0, GLX_STENCIL_SIZE, 0,
  445.                         None};
  446.  
  447.     createWindowAndContext(&dpy, &window, &ctx, 50, 0, size.xyVal.x * WINSCALE,
  448.                            size.xyVal.y * WINSCALE, GL_FALSE, NULL,
  449.                            visualAttr, argv[0]);
  450.  
  451.     glxVideoSource = glXCreateGLXVideoSourceSGIX(dpy, DefaultScreen(dpy), svr,
  452.                                                  path, VL_TEXTURE, drn);
  453.     if (glxVideoSource == None) {
  454.         fprintf(stderr, "can't create video source\n");
  455.         exit(EXIT_FAILURE);
  456.     }
  457.  
  458.     glMatrixMode(GL_TEXTURE);
  459.     glLoadMatrixf((GLfloat *) texture_matrix);
  460.     glMatrixMode(GL_PROJECTION);
  461.     glLoadIdentity();
  462.     gluOrtho2D(-10, size.xyVal.x + 10, -10, size.xyVal.y + 10);
  463.     glMatrixMode(GL_MODELVIEW);
  464.     glLoadIdentity();
  465.     glTranslatef(0, 0, -0.5);
  466.  
  467.     glXMakeCurrentReadSGI(dpy, window, glxVideoSource, ctx);
  468.     CreateTexture();
  469.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  470.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  471.     setupMaps();
  472.     glColor4f(1, 1, 1, 1);
  473. }
  474.  
  475. /*
  476.  * CreateTexture: Create a texture map with correct attributes.
  477.  */
  478. int
  479. CreateTexture()
  480. {
  481.     GLubyte fakeTexture[1024][1024][3];
  482.  
  483.     /*
  484.      * 625 textures are bigger than 525 textures
  485.      */
  486.     if (timing.intVal == VL_TIMING_525_SQ_PIX ||
  487.         timing.intVal == VL_TIMING_525_CCIR601) {
  488.     t_width = 1024;
  489.     t_height = 512;
  490.     } else {
  491.     t_width = 1024;
  492.     t_height = 1024;
  493.     }
  494.  
  495.     s_scale = (size.xyVal.x - 1)/(float) t_width;
  496.     t_scale = size.xyVal.y/(float) t_height;
  497.  
  498.     /* Sirius always transfers 768 pixels */
  499.     s_fraction = 768.0/t_width;
  500.     t_fraction = size.xyVal.y/(float) t_height;
  501.  
  502.     glEnable(GL_TEXTURE_2D);
  503.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  504.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  505.     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_EXT, t_width, t_height, 0,
  506.                  GL_RGB, GL_UNSIGNED_BYTE, fakeTexture);
  507.     texture_matrix[0][0] =  s_scale;
  508.     texture_matrix[1][1] = -t_scale;
  509.     texture_matrix[3][1] =  t_scale;
  510. }
  511.  
  512. /*
  513.  * DisplayFrame: Display a new frame.
  514.  * This routine is called at 30 Hz for 525 timing and 25Hz for 625 timing.
  515.  */
  516. void
  517. DisplayNewFrame()
  518. {
  519.     int i;
  520.     
  521.     glClear(GL_COLOR_BUFFER_BIT);
  522.     /* Load the texture from Sirius to Texture memory */
  523.     glCopyTexSubImage2DEXT(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
  524.                768, size.xyVal.y);
  525.     /* First draw a full window texture mapped polygon */
  526.     glMatrixMode(GL_TEXTURE);
  527.     glLoadMatrixf((GLfloat*) texture_matrix);
  528.     
  529.     glMatrixMode(GL_MODELVIEW);
  530.     glLoadIdentity();
  531.     glTranslatef(0, 0, -0.5);
  532.  
  533.     glEnable(GL_TEXTURE_2D);
  534.  
  535.     glBegin(GL_POLYGON);
  536.     glTexCoord2f(0, 0); glVertex2f(0, 0);
  537.     glTexCoord2f(1, 0); glVertex2f(size.xyVal.x, 0);
  538.     glTexCoord2f(1, 1); glVertex2f(size.xyVal.x, size.xyVal.y);
  539.     glTexCoord2f(0, 1); glVertex2f(0, size.xyVal.y);
  540.     glEnd();
  541.  
  542.     /* Draw the bubbles */
  543.     for (i=0; i < numBubbles; i++)
  544.         drawBubble(&bubs[i]);
  545. }
  546.  
  547. void
  548. cleanup()
  549. {
  550.     vlEndTransfer(svr, path);
  551.     vlDestroyPath(svr, path);
  552.     vlCloseVideo(svr);
  553.     exit(EXIT_SUCCESS);
  554. }
  555.  
  556. void
  557. ProcessEvents()
  558. {
  559.     VLEvent ev;
  560.  
  561.     /* Check to see if any controls changed or if the video
  562.      * path has been pre-empted.
  563.      */
  564.     if (vlCheckEvent(svr, VLControlChangedMask|
  565.                      VLStreamPreemptedMask, &ev) == -1) {
  566.     return;
  567.     }
  568.     switch(ev.reason) {
  569.       case VLStreamPreempted:
  570.         cleanup();
  571.         break;
  572.       case VLControlChanged:
  573.         switch(ev.vlcontrolchanged.type) {
  574.           case VL_TIMING:
  575.           case VL_SIZE:
  576.           case VL_PACKING:
  577.             UpdateTimingFormat();
  578.             printf("got VL_PACKING event\n");
  579.             break;
  580.           default:
  581.             break;
  582.         }
  583.             break;
  584.       default:
  585.     break;
  586.     }
  587. }
  588.  
  589. void
  590. UpdateTimingFormat()
  591. {
  592.     /* Get the timing from input source */
  593.     if (vlGetControl(svr, path, src, VL_TIMING, &timing) < 0) {
  594.     vlPerror("vlGetControl");
  595.     exit(EXIT_FAILURE);
  596.     }
  597.  
  598.     /* Set texture drain's timing to input source */
  599.     if (vlSetControl(svr, path, drn, VL_TIMING, &timing) < 0) {
  600.     vlPerror("vlSetControl");
  601.     exit(EXIT_FAILURE);
  602.     }
  603.  
  604.     if (vlGetControl(svr, path, src, VL_SIZE, &size) < 0) {
  605.     vlPerror("vlSetupPaths");
  606.     exit(EXIT_FAILURE);
  607.     }
  608. }
  609.